package org.zuma.gradle.springboot.task.oci.docker;

import cn.hutool.core.util.StrUtil;

import com.zuma.oci.docker.DockerApi;
import com.zuma.oci.docker.configuration.DockerConfigurationMetadata;
import com.zuma.oci.docker.param.ImageBuildParam;
import com.zuma.oci.docker.type.ImageBuildRegistryConfig;
import com.zuma.oci.docker.type.RegistryAuth;
import com.zuma.oci.system.Environment;
import org.gradle.api.Action;
import org.gradle.api.DefaultTask;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.MapProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.*;
import org.zuma.gradle.springboot.spec.DockerSpec;

import java.nio.file.Path;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public abstract class BuildImageWithFileTask extends DefaultTask {

    @Input
    public abstract Property<String> getImage();

    @Input
    public abstract Property<String> getTag();

    @Input
    @Optional
    public abstract Property<String> getContext();

    @InputFile
    @Optional
    public abstract Property<String> getDockerfile();

    @Input
    @Optional
    public abstract MapProperty<String, String> getBuildArgs();

    @Input
    @Optional
    public abstract Property<Boolean> getPush();


    @InputFile
    @Optional
    public RegularFileProperty getJar() {
        return this.jar;
    }

    @OutputFile
    @Optional
    public RegularFileProperty getOutJar() {
        return this.outJar;
    }

    private final RegularFileProperty jar;

    private final RegularFileProperty outJar;

    private final DockerSpec docker;


    @Nested
    public DockerSpec getDocker() {
        return this.docker;
    }

    public void docker(Action<DockerSpec> action) {
        action.execute(this.docker);
    }

    // @Inject
    public BuildImageWithFileTask() {
        this.jar = getProject().getObjects().fileProperty();
        this.outJar = getProject().getObjects().fileProperty();
        this.docker = getProject().getObjects().newInstance(DockerSpec.class);
    }

    @TaskAction
    void buildWithDockerFile() {
        try {
            var pathStr = this.getContext().getOrNull();
            var path = this.getProject().getProjectDir().toPath();
            if (pathStr != null) {
                path = Path.of(pathStr);
            }
            var imageName = this.getImage().get() + ":" + this.getTag().get();
            DockerConfigurationMetadata environmentConfiguration = DockerConfigurationMetadata.from(Environment.SYSTEM);
            Map<String, ImageBuildRegistryConfig> authConfig = new HashMap<>();
            if (environmentConfiguration != null) {
                var authMap = environmentConfiguration.getConfiguration().getAuths();
                for (var entry : authMap.entrySet()) {
                    var value = entry.getValue();
                    if (StrUtil.isNotBlank(value.getUsername()) && StrUtil.isNotBlank(value.getPassword())) {
                        authConfig.put(entry.getKey(), ImageBuildRegistryConfig.buildImageBuildRegistryConfig(value.getUsername(), value.getPassword()));
                    }
                }
            }
            var buildRegistryMap = docker.parseBuilderRegistry();
            if (!buildRegistryMap.isEmpty()) {
                for (var entry : buildRegistryMap.entrySet()) {
                    var userName = entry.getValue().getUsername();
                    var password = entry.getValue().getPassword();
                    if (StrUtil.isNotBlank(userName) && StrUtil.isNotBlank(password)) {
                        authConfig.put(entry.getKey(), ImageBuildRegistryConfig.buildImageBuildRegistryConfig(userName, password));
                    }
                }
            }
            var imageBuildParam = new ImageBuildParam();
            var argMap = this.getBuildArgs().getOrElse(Collections.emptyMap());
            if (!argMap.isEmpty()) {
                imageBuildParam.buildArgs(argMap);
            }
            imageBuildParam.dockerfile(this.getDockerfile().getOrElse("Dockerfile"));
            imageBuildParam.imageName(imageName);

            var dockerApi = new DockerApi();
            dockerApi.image().build(imageBuildParam, authConfig, path, res -> {
                if (StrUtil.isNotBlank(res.getError())) {
                    System.err.println(res.getError());
                }
                if (StrUtil.isNotBlank(res.getStream())) {
                    System.out.println(res.getStream());
                }
                if (StrUtil.isNotBlank(res.getStatus())) {
                    System.out.println(res.getStatus());
                }
            });
            if (getPush().orElse(false).get()) {
                RegistryAuth auth = null;
                if (docker.getPublishRegistry() != null) {
                    var userName = docker.getPublishRegistry().getUsername().orElse("").get();
                    var password = docker.getPublishRegistry().getPassword().orElse("").get();
                    var email = docker.getPublishRegistry().getEmail().orElse("").get();
                    var url = docker.getPublishRegistry().getUrl().orElse("").get();
                    auth = RegistryAuth.create(
                            userName,
                            password,
                            email,
                            url
                    );
                }
                dockerApi.image().push(imageName, null, auth);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
}
